using IQIGame.Onigao.Game;
using IQIGame.Onigao.Logic;
using System;
using UnityEngine;
using UnityEngine.Assertions;

namespace IQIGame.Onigao.GamePlay
{
    public class LevelMoveComponent : EntityMoveComponent
    {
        #region public properties
        //覆盖基础实体
        public LevelPlayRealityEntity entity => _entity as LevelPlayRealityEntity;

        /// <summary>
        /// Transform
        /// </summary>
        public override TransformAgent transform => entity.transform;

        /// <summary>
        /// 导航控制器
        /// </summary>
        protected override TNavigationController navigationCtrl => LevelPlayModule.Instance.levelPlay.regionCtrl.navigationCtrl;

        /// <summary>
        /// 实体身上的Collider
        /// </summary>
        public Collider collider { protected set; get; }

        /// <summary>
        /// 是否在物理行动区域
        /// </summary>
        public bool inPhysicalMoveArea { protected set; get; }

        /// <summary>
        /// 是否在锁定物理移动的状态
        /// </summary>
        public bool inLockPhysicalState => _physicTrans != null;

        /// <summary>
        /// 动画组件
        /// </summary>
        protected override EntityAnimationComponent animComponent
        {
            get
            {
                _animComponent = _animComponent ?? this.entity.GetAnimationComponent();
                return _animComponent;
            }
        }
        #endregion public properties

        #region private fields
        /// 动画组件
        /// </summary>
        private LevelAnimationComponent _animComponent;
        /// <summary>
        /// 移动方向（不需要移动时为Vector3.zero，注意该方向并未归一化）
        /// </summary>
        private int _carrierEntityId;
        private LevelMoveComponent _carrierEntityMoveCom;
        private event Action<Vector3, bool> moveDeltaEvent;
        private Transform _physicTrans;
        private Game.RectInt _physicWalkableArea;
        #endregion private fields

        public override void OnComponentEvent<T>(TComponentEvent eventType, T arg)
        {
            switch (eventType)
            {
                case TComponentEvent.OnEntityObjectLoaded:
                    if (arg is EntityLoadState loadState && (loadState == EntityLoadState.None || loadState == EntityLoadState.Error))
                    {
                        return;
                    }
                    Assert.IsNotNull(this.transform, "[LevelMoveComponent|OnCreate] Transform is null");
                    if (this.isPlayerAvatarEntity)
                    {
                        AddCharacterController();
                        return;
                    }
                    GameObject go = transform.gameObject;
                    // 其他实体，如果有碰撞体信息，需要加上
                    var dynEntity = entity.GetDynLevelEntity();
                    if (dynEntity != null)
                    {
                        var obstacle = dynEntity.levelEntityConfig.obstacle;
                        if (obstacle != null)
                        {
                            if (obstacle.isCapsule)
                            {
                                var capsuleCollider = go.GetComponent<CapsuleCollider>();
                                if (capsuleCollider == null)
                                {
                                    capsuleCollider = go.AddComponent<CapsuleCollider>();
                                }
                                capsuleCollider.radius = GameMathUtil.LogicValue2Float(obstacle.radius);
                                capsuleCollider.height = GameMathUtil.LogicValue2Float(obstacle.height);
                                capsuleCollider.center = new Vector3(0, capsuleCollider.height / 2, 0);
                                this.collider = capsuleCollider;
                            }
                            else
                            {
                                var boxCollider = go.GetComponent<BoxCollider>();
                                if (boxCollider == null)
                                {
                                    boxCollider = go.AddComponent<BoxCollider>();
                                }
                                boxCollider.size = new Vector3(GameMathUtil.LogicValue2Float(obstacle.rectW), GameMathUtil.LogicValue2Float(obstacle.height), GameMathUtil.LogicValue2Float(obstacle.rectH));
                                boxCollider.center = new Vector3(GameMathUtil.LogicValue2Float(obstacle.x), GameMathUtil.LogicValue2Float(obstacle.height) / 2, GameMathUtil.LogicValue2Float(obstacle.y));
                                this.collider = boxCollider;
                            }
                            SetColliderActive(dynEntity.isObstacleActive);
                        }
                    }
                    break;

                case TComponentEvent.OnEntityObjectStartHide:
                    OnHide();
                    break;
            }
        }

        protected override void OnHide()
        {
            base.OnHide();
            SetColliderActive(false);
        }

        /// <summary>
        /// 设置为主角
        /// </summary>
        /// <param name="active"></param>
        public void SetAsMainCharacter(bool active)
        {
            this.isPlayerAvatarEntity = active;
        }

        /// <summary>
        /// 设置Collider是否激活
        /// </summary>
        /// <param name="active"></param>
        public void SetColliderActive(bool active)
        {
            if (this.collider == null)
            {
                return;
            }
            this.collider.enabled = active;
        }

        protected override bool MoveStepInner(Vector3 pos, out Vector3 realPos)
        {
            if (_physicTrans != null) //在物理范围内且启动物理寻路（设置物理寻路实体）
            {
                //基于物理移动
                return PhysicalMoveStep(pos, out realPos);
            }
            else
            {
                return NavigationMoveStep(pos, out realPos);
            }
        }

        /// <summary>
        /// 基于物理移动
        /// </summary>
        /// <param name="tryEndPos"></param>
        /// <param name="realEndPos"></param>
        /// <returns></returns>
        public bool PhysicalMoveStep(Vector3 tryEndPos, out Vector3 realEndPos)
        {
            //射线检测来修正脚底高度
            //只有当脚下有Collider时才处于正确的物理寻路区域
            if (TryPhysicMove(tryEndPos, out realEndPos))
            {
                var postionDelta = realEndPos - transform.position;
                if (_carrierEntityId != 0) //载具模式，忽略地面和碰撞，跟随载具移动
                {
                    transform.position = realEndPos;
                }
                else
                {
                    characterController.Move(postionDelta);
                }
                return true;
            }
            return false;
        }

        private bool TryPhysicMove(Vector3 footPosition, out Vector3 physicPos)
        {
            float physicY = _physicTrans.position.y;
            float curY = footPosition.y;
            //高度超出范围直接认为移动失败
            //目前是只需要判断一个二维平面，就单独特殊计算了高度，如果以后需要判断一个三维BOX，这里需要调整
            if (Math.Abs(physicY - curY) > 20)
            {
                physicPos = Vector3.zero;
                return false;
            }
            var physicEntityPos = _physicTrans.position;
            //RectInt的xy实际上是左下角，但我们配置时为了方便是当做Center来配的，所以这里要转换一下
            float rectBottomLeftOffsetX = (_physicWalkableArea.X - _physicWalkableArea.Width * 0.5f) / LgLevelConst.DistanceUnitRatio;
            float rectBottomLeftOffsetY = (_physicWalkableArea.Y - _physicWalkableArea.Height * 0.5f) / LgLevelConst.DistanceUnitRatio;
            Rect worldPhysicArea = new Rect(
                physicEntityPos.x + rectBottomLeftOffsetX,
                physicEntityPos.z + rectBottomLeftOffsetY,
                (float)_physicWalkableArea.Width / LgLevelConst.DistanceUnitRatio,
                (float)_physicWalkableArea.Height / LgLevelConst.DistanceUnitRatio);
            bool isInArea = worldPhysicArea.Contains(new Vector2(footPosition.x, footPosition.z));
            if (isInArea)
            {
                physicPos = new Vector3(footPosition.x, physicY, footPosition.z);
                return true;
            }
            float nearestX = Math.Max(worldPhysicArea.min.x, Math.Min(footPosition.x, worldPhysicArea.max.x));
            float nearestZ = Math.Max(worldPhysicArea.min.y, Math.Min(footPosition.z, worldPhysicArea.max.y));
            physicPos = new Vector3(nearestX, physicY, nearestZ);
            return true;
        }

        /// <summary>
        /// 开始物理移动。
        /// </summary>
        /// <param name="active"></param>
        public void SwtichPhysicalMovement(bool active)
        {
            if (inLockPhysicalState)
            {
                return;
            }
            if (inPhysicalMoveArea == active)
            {
                return;
            }
            inPhysicalMoveArea = active;
#if UNITY_EDITOR
            if (!active)
            {
                Debug.Log("End Physical Move");
            }
            else
            {
                Debug.Log("Enter Physical Move Area!");
            }
#endif
        }

        /// <summary>
        /// 锁定物理移动中
        /// </summary>
        /// <param name="lockPhysicalMove"></param>
        public void LockPhysicalMovement(Transform physicTrans, Game.RectInt walkableArea)
        {
            if (this._physicTrans == physicTrans)
            {
                return;
            }
            this._physicTrans = physicTrans;
            this._physicWalkableArea = walkableArea;
        }

        public override uint MaxStore => 50;

        public override void OnPoolReset()
        {
            _animComponent = null;
            moveDeltaEvent = null;
            _carrierEntityId = 0;
            if (_carrierEntityMoveCom != null)
            {
                _carrierEntityMoveCom.moveDeltaEvent -= UpdatePosFollowCarrier;
                _carrierEntityMoveCom = null;
            }
            _physicTrans = null;
            this.collider = null;
        }


        #region SmoothMove
        /// <summary>
        /// 实体重置时全量刷新位置和旋转
        /// </summary>
        public void SyncPositionAndRotation(float x, float y, float z, Vector3 eulerAngle)
        {
            var currentPositon = LevelPlayUtil.GetAdjustedPosByGround(x, y, z);
            StopAndSetPosition(currentPositon);
            this.transform.eulerAngles = eulerAngle;
        }

        /// <summary>
        /// 根据载具的事件修改乘坐者的位置
        /// </summary>
        /// <param name="carrierMoveDelta"></param>
        /// <param name="isStopped"></param>
        private void UpdatePosFollowCarrier(Vector3 carrierMoveDelta, bool isStopped)
        {
            SetPosition(this.transform.position + carrierMoveDelta);
            this.entity.TransPosToData();
            if (isStopped && _carrierEntityId == 0)
            {
                ClearCarrier();
            }
        }

        /// <summary>
        /// 统一的设置坐标方法
        /// 所有transform.position = position都必须通过它来实现
        /// </summary>
        /// <param name="position"></param>
        /// <param name="isMoving"></param>
        protected override void SetPosition(Vector3 position, bool isMoving = false)
        {
            var moveDelta = position - transform.position;
            base.SetPosition(position);
            moveDeltaEvent?.Invoke(moveDelta, !isMoving);
        }

        #endregion

        /// <summary>
        /// 改变载具
        /// </summary>
        /// <param name="carrierEntityId"></param>
        /// <param name="isRemoved"></param>
        public void ChangeCarrier(int carrierEntityId, bool isRemoved)
        {
            if (isRemoved) //移除载具
            {
                _carrierEntityId = 0;
            }
            else
            {
                //添加载具但此时载具不为空，可能是因为由于网络延迟，服务器载具已清空，但客户端载具还在进行最后的缓动，
                //直到UpdatePosFollowCarrier中isStopped参数为true
                //此时强制清空
                if (_carrierEntityId != 0 || _carrierEntityMoveCom != null)
                {
                    ClearCarrier();
                }
                Game.RectInt walkableArea = Game.RectInt.Empty;
                Transform trans = null;
                if (_carrierEntityId != carrierEntityId || _carrierEntityMoveCom == null)
                {
                    if (LevelPlayModule.Instance.levelPlay.regionCtrl.entityCtrl.entitys.TryGetValue(carrierEntityId, out var entity))
                    {
                        if (entity is LevelNormalEntity normalEntity)
                        {
                            _carrierEntityMoveCom = normalEntity.GetMoveComponent();
                            _carrierEntityMoveCom.moveDeltaEvent += UpdatePosFollowCarrier;

                            trans = normalEntity.transform;

                            if (normalEntity.GetDynLevelEntity().levelEntityConfig.paramMap.TryGetValue(EntityDynamicParamType.TriggerRect, out var dynParam))
                            {
                                var rectParam = dynParam as EntityParamTriggerRect;
                                if (rectParam.isPhysicNavTrigger || !rectParam.isRotatable)
                                {
                                    walkableArea = rectParam.rect;
                                }
                            }

                            if (normalEntity.interactType != 0 && normalEntity.interactType != 1)
                            {
                                normalEntity.SetInteractType(1);
                            }
                        }
                    }
                }
                _carrierEntityId = carrierEntityId;
                LockPhysicalMovement(trans, walkableArea);
            }
        }

        private void ClearCarrier()
        {
            _carrierEntityMoveCom.moveDeltaEvent -= UpdatePosFollowCarrier;
            (_carrierEntityMoveCom.entity as LevelNormalEntity).RecoverInteractType();
            _carrierEntityMoveCom = null;
            LockPhysicalMovement(null, Game.RectInt.Empty);
        }
    }
}